#include <iostream>
#include <cstdio>
#include <fstream>
#include <sstream>
#include <iterator>
#include <vector>
#include <map>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include "metodos.h"
#include "resolver.h"

using namespace std;

static ostream & printVector(ostream & os, const vint & v){
	for(unsigned int i = 0; i < v.size(); i++){
		os << (v[i]+1);

		if(i+1 < v.size())
			os << " ";
	}
	
	os << endl;
	return os;
}

//Genera el nombre del archivo de salida.
static string archivoSalida(const char * entrada, const char * metodo){
	string s(entrada);
	size_t found = s.rfind(".in");
	if(found != string::npos)
		s.replace(found,s.size(),string(metodo) + string(".out"));
	return s;
}

static const char * nombres[] = {"Exacto","Goloso","Local","Grasp"};
static Metodo metodos[] = {exacto,goloso,local,grasp};
static const int NMETODOS = 4;

static vector<int> aCorrer(const char * s){
	string str(s);
	replace(str.begin(),str.end(),':',' ');

	vector<string> partes;
	istringstream ss(str);	
	copy(istream_iterator<string>(ss),
		istream_iterator<string>(),back_inserter(partes));
	
	int elegidos = partes.size();
	vector<int> indices;
	bool usado[NMETODOS];
	fill(usado,usado+NMETODOS,false);

	for(int i = 0; i < elegidos; i++){
		int ind = -1;
		for(int j = 0; j < NMETODOS; j++)
			if(!strcmp(partes[i].c_str(),nombres[j]))
				ind = j;

		if(ind < 0){
			cerr << partes[i] << " no es un metodo de resolucion valido" << endl;
			exit(0);
		}else if(usado[ind]){
			cerr << partes[i] << " ya fue considerado. Ignorando" << endl;
		}else{
			indices.push_back(ind);
			usado[ind] = true;
		}
	}
	return indices;
}
static const string separador(80,'=');
//Codigo que efectivamente corre la entrega pedida
void entrega(const char * archivoEntrada,
		const char * encMetodosACorrer,
		int itersLocal, int itersGrasp, 
		int itersLocalGrasp, int porcentaje){

	string buffer;
	ifstream entrada;

	entrada.open(archivoEntrada);
	ofstream salida[NMETODOS];

	vector<int> indices = aCorrer(encMetodosACorrer);
	int total = indices.size();
	
	for(int i = 0; i < total; i++){
		int m = indices[i];
		salida[m].open(
			archivoSalida(archivoEntrada,nombres[m]).c_str());
	}

	while(getline(entrada,buffer)){
		int nodos, aristas = 0; 
		stringstream toks(buffer);
		toks >> nodos;
		
		Grafo grafo(nodos);
		
		for(int nodo = 1; nodo < nodos; nodo++){
			getline(entrada,buffer);
			toks.clear(); toks.str(buffer);

			int vecino;
			while(toks >> vecino){
				aristas++;
				grafo.agregarEje(vecino-1,nodo);
			}
		}
		
		iteracionesLocal((4+grafo.nodos())/5);
		iteracionesGrasp(itersGrasp);
		iteracionesLocalGrasp((14+grafo.nodos())/15);
		porcentajeGrasp(porcentaje);

		cout << nodos << " " << aristas << " ";

		for(int i = 0; i < total; i++){
			int m = indices[i];
			long timer = 0;
			vint res = resolver(grafo,metodos[m],timer);
			printVector(salida[m],res);
		
			cout << res.size() << " " << timer;
		}
		cout << endl;
	}
	
	for(int i = 0; i < total; i++){
		int m = indices[i];
		salida[m].close();
	}
	entrada.close();
}


int main(int argc, const char * argv[]){
	const char * entrada =
		(argc < 2) ? "Tp3.in" : argv[1];
	const char * metodosACorrer =
		(argc < 3) ? "Exacto:Goloso:Local:Grasp" : argv[2];

	int iterLocal = -1, iterGrasp = 1000,
	    iterLocalGrasp = -1, porcentaje = 30;
	
	int *asignar[] = {&iterLocal,&iterGrasp,&iterLocalGrasp,&porcentaje};
	const int MAXPARAMS = 6;

	for(int i = 3; i < argc && i < MAXPARAMS; i++){
		*(asignar[i-3]) = atoi(argv[i]);
	}

	entrega(entrada,metodosACorrer,iterLocal,iterGrasp,iterLocalGrasp,porcentaje);
	return 0;
}
